import 'dart:async';
import 'dart:io';
import 'dart:math';
import 'dart:typed_data';
import 'package:flutter/cupertino.dart';
import 'package:image/image.dart' as img;
import 'dart:ui' as ui;
import 'package:flutter/material.dart';
import 'package:path_provider/path_provider.dart';

import '../graffiti/GraffitiSourceBean.dart';
import 'GifSourceBean.dart';

class GifDecoder {
  static Future<img.Image> case2ImgImage(ui.Image uiImg, {bool isSingleColor = false}) async {
    final byteData = await uiImg.toByteData(format: ui.ImageByteFormat.rawRgba);
    var uint32List = byteData?.buffer.asUint32List();
    final image = img.Image(width: uiImg.width, height: uiImg.height);

    for (var i = 0; i < image.height; i++) {
      for (var j = 0; j < image.width; j++) {
        var pixel = uint32List![i * image.width + j];
        int a = (pixel >> 24) & 0xff;
        int b = (pixel >> 16) & 0xff;
        int g = (pixel >> 8) & 0xff;
        int r = pixel & 0xff;
        image.setPixel(j, i, img.ColorRgba8(r, g, b, a));
      }
    }

    if (isSingleColor) {
      return singleColorImage(image);
    }
    return image;
  }

  ///计算平均灰度
  static int getAvgGray(img.Image image) {
    final width = image.width.toInt();
    final height = image.height.toInt();

    // 计算所有像素的总灰度值
    int totalGray = 0;
    int count = 0;
    for (int x = 0; x < width; x++) {
      for (int y = 0; y < height; y++) {
        var c = image.getPixel(x, y);
        var b = c.b;
        var g = c.g;
        var r = c.r;
        if (r == 0 && g == 0 && b == 0) {
          continue;
        }
        final gray = (0.299 * b + 0.587 * g + 0.114 * r).round();
        totalGray += gray;
        count++;
      }
    }
    // 计算平均灰度值
    return totalGray ~/ count;
  }

  ///转单色图
  static Future<img.Image> singleColorImage(img.Image image) async {
    final singleColorImage = img.Image(width: image.width, height: image.height, numChannels: 4);
    // 计算平均灰度值
    final avgGray = getAvgGray(image);
    for (int x = 0; x < image.width; x++) {
      for (int y = 0; y < image.height; y++) {
        var c = image.getPixel(x, y);
        var b = c.b;
        var g = c.g;
        var r = c.r;
        final gray = (0.299 * b + 0.587 * g + 0.114 * r).round();
        var color = gray >= avgGray ? Colors.white : Colors.black;
        singleColorImage.setPixel(x, y, img.ColorRgba8(color.red, color.green, color.blue, color.alpha));
      }
    }
    return singleColorImage;
  }


  static Future<ui.Image> resizeImage(ui.Image image, Size size) async {
    final recorder = ui.PictureRecorder();
    final canvas = Canvas(recorder);
    final paint = Paint();
    paint.isAntiAlias = false;
    //canvas.drawImage(image, Offset.zero, paint);
    //计算居中后的尺寸和位置

    var s = size.width / image.width;
    if (s * image.height > size.height) {
      s = size.height / image.height;
    }

    var dw = image.width * s;
    var dh = image.height * s;

    var dx = (size.width - dw) / 2;
    var dy = (size.height - dh) / 2;

    canvas.drawImageRect(image, Rect.fromLTWH(0, 0, image.width.toDouble(), image.height.toDouble()),
        Rect.fromLTWH(dx, dy, dw, dh), paint);
    final picture = recorder.endRecording();
    return picture.toImage(size.width.toInt(), size.height.toInt());
  }

  //变形压缩
  static Future<ui.Image> resizeImageEz(ui.Image image, Size size) async {
    final recorder = ui.PictureRecorder();
    final canvas = Canvas(recorder);
    final paint = Paint();
    paint.isAntiAlias = false;
    //canvas.drawColor(GraffitiBean().getDefaultColor(), BlendMode.src);
    canvas.drawImageRect(image, Rect.fromLTWH(0, 0, image.width.toDouble(), image.height.toDouble()),
        Rect.fromLTWH(0, 0, size.width, size.height), paint);
    final picture = recorder.endRecording();
    return picture.toImage(size.width.toInt(), size.height.toInt());
  }

  static Future<ui.Image> case2UiImage(img.Image decodeFrame) async {
    final recorder = ui.PictureRecorder();
    final canvas = Canvas(recorder);
    final paint = Paint();
    paint.isAntiAlias = false;

    for (var y = 0; y < decodeFrame.height; y++) {
      for (var x = 0; x < decodeFrame.width; x++) {
        Color color;
        var pixel = decodeFrame.getPixel(x, y);
        var a = pixel.a;
        var r = pixel.r;
        var g = pixel.g;
        var b = pixel.b;
        color = Color.fromARGB(a.toInt(), r.toInt(), g.toInt(), b.toInt());
        paint.color = color;
        canvas.drawRect(Rect.fromLTWH(x.toDouble(), y.toDouble(), 1, 1), paint);
      }
    }

    final picture = recorder.endRecording();
    return picture.toImage(decodeFrame.width, decodeFrame.height);
  }

  static Future<ui.Image> graffitiBean2UiImage(GraffitiSourceBean bean) async {
    final recorder = ui.PictureRecorder();
    final canvas = Canvas(recorder);
    final paint = Paint();
    paint.isAntiAlias = false;
    /* var drawBean = bean.getDrawCanvasBean();
    for (var y = 0; y < bean.screenSize.height; y++) {
      for (var x = 0; x < bean.screenSize.width; x++) {
        Color color;
        var pixel = drawBean.getPoint(x, y);
        if (pixel != null) {
          color = pixel;
          paint.color = color;
          canvas.drawRect(Rect.fromLTWH(x.toDouble(), y.toDouble(), 1, 1), paint);
        }
      }
    }*/

    final picture = recorder.endRecording();
    return picture.toImage(bean.screenSize.width.toInt(), bean.screenSize.height.toInt());
  }

  static Future<String> resizeGif(Uint8List bytes, Size size) async {
    var decoder = img.GifDecoder(bytes);

    var info = decoder.info!;

    List<ui.Image> imgImageList = [];
    ui.Image srcImage;
    var recorder = ui.PictureRecorder();
    var canvas = Canvas(recorder);
    final paint = Paint();
    paint.isAntiAlias = false;

    for (var i = 0; i < decoder.numFrames(); i++) {
      var decodeFrame = decoder.decodeFrame(i);
      if (decodeFrame == null) {
        continue;
      }
      int offsetX = info.frames[i].x;
      int offsetY = info.frames[i].y;
      for (var y = 0; y < decodeFrame.height; y++) {
        for (var x = 0; x < decodeFrame.width; x++) {
          Color color;
          var pixel = decodeFrame.getPixel(x, y);
          var a = pixel.a;
          var r = pixel.r;
          var g = pixel.g;
          var b = pixel.b;
          if (i == 0) {
            color = Color.fromARGB(a.toInt(), r.toInt(), g.toInt(), b.toInt());
          } else {
            if (a == 0) {
              if (decodeFrame.width - offsetX != info.width || decodeFrame.height - offsetY != info.height) {
                continue;
              } else {
                color = Color.fromARGB(a.toInt(), r.toInt(), g.toInt(), b.toInt());
              }
            } else {
              color = Color.fromARGB(a.toInt(), r.toInt(), g.toInt(), b.toInt());
            }
          }

          paint.color = color;
          canvas.drawRect(Rect.fromLTWH((x + offsetX).toDouble(), (y + offsetY).toDouble(), 1, 1), paint);

          //srcImage.setPixel(x + offsetX, y + offsetY, pixel);
        }
      }

      final picture = recorder.endRecording();
      srcImage = await picture.toImage(info.width, info.height);
      imgImageList.add(srcImage);
      //复制一份
      recorder = ui.PictureRecorder();
      canvas = Canvas(recorder);
      canvas.drawImage(srcImage, ui.Offset.zero, paint);
    }

    List<ui.Image> imgList = imgImageList;

    //重制尺寸
    List<ui.Image> resizeImgList = [];
    for (var img in imgList) {
      var i = await resizeImage(img, size);
      resizeImgList.add(i);
    }
    //时间信息
    List<int> delays = [];
    for (var i = 0; i < decoder.numFrames(); i++) {
      delays.add(info.frames[i].duration);
    }
    return await case2Gif(resizeImgList, delays);
  }

  static Future<String> case2Gif(List<ui.Image> list, List<int> delays) async {
    final img.GifEncoder encoder = img.GifEncoder(samplingFactor: 1);
    final List<int> gifBytes = [];

    for (var i = 0; i < list.length; i++) {
      final image = await case2ImgImage(list[i]);
      encoder.addFrame(image, duration: delays[i]);
    }

    var finish = encoder.finish()!;

    for (var f in finish) {
      gifBytes.add(f);
    }

    final Directory appDocumentsDir = await getApplicationDocumentsDirectory();

    print("appDocumentsDir:${appDocumentsDir.path}");
    var outputPath = "${appDocumentsDir.path}/source/";

    await Directory(outputPath).create(recursive: true);
    outputPath = "$outputPath${DateTime.now().millisecondsSinceEpoch}.gif";

    // 3. 保存GIF动画到文件
    final File outputFile = File(outputPath);
    outputFile.writeAsBytesSync(gifBytes);

    print('GIF created successfully.$outputPath');
    return outputPath;
  }

  static Future<ui.Image> decodeImage(Uint8List byteData) {
    // 将字节数据转换为 Uint8List
    final buffer = byteData.buffer;
    // 创建一个 Completer 用于异步获取图像
    final completer = Completer<ui.Image>();
    // 解码图片
    ui.decodeImageFromList(
      buffer.asUint8List(),
      (ui.Image img) async {
        // 图像解码完成后，将图像传递给 Completer
        completer.complete(img);
      },
    );
    return completer.future;
  }

  static Future<String> graffitiBean2Gif(List<GraffitiSourceBean> graffitiBeans, Size size, List<int> delays) async {
    List<ui.Image> list = [];
    /*for (var graffitiBean in graffitiBeans) {
      var img = await graffitiBean.getImage();
      list.add(img);
    }*/
    return case2Gif(list, delays);

    /*List<String> fileList = [];
    for (var graffitiBean in graffitiBeans) {
      var img = await graffitiBean2Png(graffitiBean, "${DateTime.now().microsecondsSinceEpoch}.png");
      fileList.add(img);
    }

    // 获取应用的临时目录
    final directory = await getApplicationDocumentsDirectory();
    final Directory d = Directory('${directory.path}/source/');
    d.createSync(recursive: true);
    final filePath = '${directory.path}/source/${DateTime.now().microsecondsSinceEpoch}.gif';

    var path = await createGif(
        files: fileList,
        outputPath: filePath,
        frameDelays: delays,
        width: size.width.toInt(),
        height: size.height.toInt());

    //删除临时数据
    for (var file in fileList) {
      File(file).deleteSync();
    }
    return filePath;*/
  }

  static Future<GraffitiSourceBean> uiImage2GraffitiBean(ui.Image image, Size size) async {
    GraffitiSourceBean graffitiBean = GraffitiSourceBean();
    graffitiBean.screenSize = size;
    final byteData = await image.toByteData(format: ui.ImageByteFormat.rawRgba);
    var uint32List = byteData?.buffer.asUint32List();
    /*for (var i = 0; i < image.height; i++) {
      for (var j = 0; j < image.width; j++) {
        var pixel = uint32List![i * image.width + j];
        int a = (pixel >> 24) & 0xff;
        int b = (pixel >> 16) & 0xff;
        int g = (pixel >> 8) & 0xff;
        int r = pixel & 0xff;
        graffitiBean.drawPoint(j, i, color: Color.fromARGB(a.toInt(), r.toInt(), g.toInt(), b.toInt()));
      }
    }
    graffitiBean.saveRecord();*/
    return graffitiBean;
  }

  static Future<List<GraffitiSourceBean>> gif2GraffitiBean(Uint8List byteData, Size size) async {
    List<ui.Image> imgImageList = [];
    /*   var decoder = img.GifDecoder(byteData);
    var info = decoder.info!;

    ui.Image srcImage;
    var recorder = ui.PictureRecorder();
    var canvas = Canvas(recorder);
    final paint = Paint();
    paint.isAntiAlias = false;

    for (var i = 0; i < decoder.numFrames(); i++) {
      var decodeFrame = decoder.decodeFrame(i);
      if (decodeFrame == null) {
        continue;
      }
      int offsetX = info.frames[i].x;
      int offsetY = info.frames[i].y;
      for (var y = 0; y < decodeFrame.height; y++) {
        for (var x = 0; x < decodeFrame.width; x++) {
          Color color;
          var pixel = decodeFrame.getPixel(x, y);
          var a = pixel.a;
          var r = pixel.r;
          var g = pixel.g;
          var b = pixel.b;
          if (i == 0) {
            color = Color.fromARGB(a.toInt(), r.toInt(), g.toInt(), b.toInt());
          } else {
            if (a == 0) {
              continue;
            } else {
              color = Color.fromARGB(a.toInt(), r.toInt(), g.toInt(), b.toInt());
            }
          }

          paint.color = color;
          canvas.drawRect(Rect.fromLTWH((x + offsetX).toDouble(), (y + offsetY).toDouble(), 1, 1), paint);

          //srcImage.setPixel(x + offsetX, y + offsetY, pixel);
        }
      }

      final picture = recorder.endRecording();
      srcImage = await picture.toImage(info.width, info.height);
      imgImageList.add(srcImage);
      //复制一份
      recorder = ui.PictureRecorder();
      canvas = Canvas(recorder);
      canvas.drawImage(srcImage, ui.Offset.zero, paint);
    }*/

    // 创建 ImageDecoder
    final ui.Codec codec = await ui.instantiateImageCodec(byteData);
    // 解码 GIF 的每一帧
    for (int i = 0; i < codec.frameCount; i++) {
      final ui.FrameInfo frameInfo = await codec.getNextFrame();
      imgImageList.add(frameInfo.image);
    }

    //重制尺寸
    List<ui.Image> resizeImgList = [];
    for (var img in imgImageList) {
      var i = await resizeImage(img, size);
      resizeImgList.add(i);
    }

    List<GraffitiSourceBean> list = [];

    for (var img in resizeImgList) {
      var tmpb = await uiImage2GraffitiBean(img, size);

      //防止id重复
      bool isIdExist = true;
      while (isIdExist) {
        isIdExist = false;
        for (var b in list) {
          if (tmpb.id == b.id) {
            isIdExist = true;
            break;
          }
        }
        if (isIdExist) {
          tmpb.id = tmpb.createId();
        }
      }
      list.add(tmpb);
    }

    return list;
  }

  static Future<GifSourceBean> gif2GifBean(Uint8List byteData, Size size) async {
    GifSourceBean gifBean = GifSourceBean();
    gifBean.screenSize = size;
    gifBean.speed = getGifDelay(byteData);
    var list = await gif2GraffitiBean(byteData, size);
    gifBean.frameList = list;

    return gifBean;
  }

  static int getGifDelay(Uint8List byteData) {
    var decoder = img.GifDecoder(byteData);

    double time = 0;
    var info = decoder.info;
    if (info != null) {
      for (var i = 0; i < decoder.numFrames(); i++) {
        time += max(4, info.frames[i].duration) * 10;
        //print("动画时长：${info.frames[i].duration}");
      }

      var tmpD = time / info.frames.length / 20;
      tmpD = max(1, tmpD);
      tmpD = min(40, tmpD);
      print("播放速度：${tmpD}");
      return tmpD.toInt();
    }
    return 1;
  }

  static bool isGif(Uint8List bytes) {
    return bytes[0] == 71 && bytes[1] == 73 && bytes[2] == 70 && bytes[3] == 56;
  }

  static Future<String> graffitiBean2Png(GraffitiSourceBean graffitiBean, String fileName) async {
    return imgImage2Png(graffitiBean.getImage()!, fileName);
  }

  static Future<String> image2Png(ui.Image image, String fileName) async {
    final tmpImage = await case2ImgImage(image);
    return imgImage2Png(tmpImage, fileName);
  }

  static Future<String> imgImage2Png(img.Image image, String fileName) async {
    final png = img.encodePng(image);
    return save2File(png, fileName);
  }

  static Future<String> save2File(Uint8List bytes, String fileName) async {
    // 获取应用的临时目录
    final directory = await getApplicationDocumentsDirectory();
    final Directory d = Directory('${directory.path}/source/');
    d.createSync(recursive: true);
    final filePath = '${directory.path}/source/${fileName}';
    //File file = File(filePath);
    //file.createSync();
    print("文件路径${filePath}");
    // Write the PNG formatted data to a file.
    await File(filePath).writeAsBytes(bytes);
    return filePath;
  }
}
